#include <math.h>
 


#include <stdio.h>
#include <assert.h>

#include <iostream>
#include <GL/glew.h>
#include <GL/glut.h>

#include "RayCaster.h"
#include "TransferFunction.h"
#include <GL/glui.h>

#pragma comment(lib, "glew32.lib")


const char *TF_string_list[] = { "SolidStyle1", "SolidStyle2","TransparentSytle1", "TransparentSytle2" };
int   curr_string = 0;


using namespace std;
int w=800;
int h=800;
//=====App===status================
GLUI *glui;
int window_id;




float stepsize = 0.0006980;
float isovalue = 0.2;
float selectOuput = 0.1;
//=================================

float view_rotate[16] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 };
float obj_pos[] = { 0.0, 0.0, 0.0 };
//
int last_x, last_y;
int button, button_state;
float rotationX, rotationY;



//=================================
RayCaster *raycaster;
TransferFunction *transferfunction;
void display()                              
{
    //glui->sync_live();

	raycaster->setRotationMatrix(view_rotate);
	raycaster->setTranslation(obj_pos);
	raycaster->setStepSize(stepsize);
	raycaster->setIsoValue(isovalue);
	//if(isovalue>0.5 && isovalue <0.8)
		raycaster->Render();
	//else if(isovalue <0.5)
//	raycaster->ImageSpaceAdaptiveRender(selectOuput);
			//raycaster->ImageSpaceAdaptiveRender2();
	//else
		//raycaster->RenderDemo();

	//transferfunction->Render();

	glutSwapBuffers();
}

void idle(void)                                 
{
	glutSetWindow(window_id);
	glutPostRedisplay();
}

void reshape (int w, int h)
{
	//glViewport(0, 0, w, h); 
 //   glMatrixMode(GL_PROJECTION);
 //   glLoadIdentity();
 //   gluPerspective(45.0, w/h, 1.0, 25.0);
 //   glMatrixMode(GL_MODELVIEW);
 //   glLoadIdentity();
 //   gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

void keyboard(unsigned char key, int x, int y)  { }

void mouse(int button, int state, int x, int y) 
{
  
  //if ( button == GLUT_LEFT_BUTTON && button_state == GLUT_DOWN ) {
  //  last_x = x;
  //  last_y = y;
  //}

  transferfunction->MouseButton(button, state, x, h-y);
}
void move(int x, int y)                         
{
  //rotationX -= (float) (y - last_y)/5;
  //rotationY += (float) (x - last_x)/5;
  //raycaster->setRotation(rotationX, rotationY);
  transferfunction->MouseMove(x,h-y);
  

  //last_x = x;
  //last_y = y;

  glutPostRedisplay(); 

}
void init_gl()
{
    glewInit();
    if (!glewIsSupported("GL_VERSION_2_0 GL_EXT_framebuffer_object")) {
        printf("Required extensions not supported.\n");
        exit(-1);
		if (!GLEW_EXT_texture3D)
			exit(-1);
    }
	char* version = (char*)glGetString(GL_VERSION);

	glClearColor(0.2, 0.2, 0.2, 1.0);

	raycaster->LoadVolume("head256X256X256.raw");
	raycaster->InitializeRayCaster();
	
	transferfunction = new TransferFunction();
	transferfunction->setHistogram(raycaster->getHistogram());

	raycaster->setTransferFunctionTexture(transferfunction->getTexture());
	//for GS
}

void Save(int control)
{
	transferfunction->SavetoFile(TF_string_list[curr_string]);
}

void Apply(int control)
{
	transferfunction->LoadfromFile(TF_string_list[curr_string]);
}

int main(int argc, char* argv[])
{

	glutInit(&argc, argv);
	glutInitWindowSize(w, h);

	glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB | GLUT_STENCIL);

	window_id = glutCreateWindow("GPU RayCaster");

	raycaster = new RayCaster(w,h);
	init_gl();
	transferfunction->LoadfromFile("SolidStyle2");

 
	glutDisplayFunc(display); 
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMouseFunc(mouse);
	glutMotionFunc(move);
	//glutIdleFunc(idle);


	//GLUI
	
    glui = GLUI_Master.create_glui( "GLUI", 0, 700, 400); 
    GLUI_Rotation *view_rot = new GLUI_Rotation(glui, "Objects", view_rotate );
	view_rot->set_spin( 1.0 );
	
	//new GLUI_Column( glui, true);
	
  
	GLUI_Translation *trans_xy = new GLUI_Translation(glui, "Objects XY", GLUI_TRANSLATION_XY, obj_pos );
	trans_xy->set_speed( .005 );
    //new GLUI_Column( glui, true );
  
	GLUI_Translation *trans_x = new GLUI_Translation(glui, "Objects X", GLUI_TRANSLATION_X, obj_pos );
    trans_x->set_speed( .005 );

	//new GLUI_Column( glui, false );
    GLUI_Translation *trans_y = new GLUI_Translation( glui, "Objects Y", GLUI_TRANSLATION_Y, &obj_pos[1] );
	trans_y->set_speed( .005 );
	
	//new GLUI_Column( glui, false );
	GLUI_Translation *trans_z = new GLUI_Translation( glui, "Objects Z", GLUI_TRANSLATION_Z, &obj_pos[2] );
	trans_z->set_speed( .005 );

	GLUI_Panel *raycaster_panel = new GLUI_Panel( glui, "RayCaster Parameters" );
    GLUI_Spinner *GUIstepsize = new GLUI_Spinner( raycaster_panel, "Stepsize", &stepsize);
	GUIstepsize->set_float_limits( 0.00002f, 0.01f );
    GUIstepsize->set_alignment( GLUI_ALIGN_RIGHT );

    GLUI_Spinner *GUIisovalue = new GLUI_Spinner( raycaster_panel, "Methods", &isovalue);
	GUIisovalue->set_float_limits( 0.01f, 1.0f );
    GUIisovalue->set_alignment( GLUI_ALIGN_RIGHT );

 //   GLUI_Spinner *GUIselect = new GLUI_Spinner( raycaster_panel, "selectOuput", &selectOuput);
	//GUIselect->set_float_limits( 0.01f, 1.0f );
 //   GUIselect->set_alignment( GLUI_ALIGN_RIGHT );

	//List box
	GLUI_Listbox *list = new GLUI_Listbox( glui, "Render Style", &curr_string );	 
	for(int i=0; i<4; i++ )
    list->add_item( i, TF_string_list[i] );

	//new GLUI_StaticText( glui, "" );
	glui->add_button("Apply Style",0,Apply);
	glui->add_button("Save Style",0,Save);


	glui->set_main_gfx_window( window_id );
    
	GLUI_Master.set_glutIdleFunc( idle ); 
	
	glutMainLoop();

	return 0;
}

